﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Data;
using System.Data.Objects;
using System.Reflection;

namespace Sita.Data.Context
{
    public partial class SitaContext : ISitaContext
    {
        #region  IQueryableContext

        public new string DefaultContainerName
        {
            get { return base.DefaultContainerName; }
        }

        public void SetChanges<TEntity>(TEntity item) where TEntity : class, Sita.Entities.IObjectWithChangeTracker, new()
        {
            Type MatchType;
            PropertyInfo[] Properties;

            MatchType = typeof(ObjectSet<>).MakeGenericType(typeof(TEntity));
            Properties = this.GetType().GetProperties();

            foreach (PropertyInfo PropInfo in Properties)
            {
                if (PropInfo.PropertyType == MatchType)
                {
                    ((ObjectSet<TEntity>)PropInfo.GetValue(this, null)).ApplyChanges<TEntity>(item);
                    return;
                }
            }
            throw new InvalidOperationException();
        }

        public void Attach<TEntity>(TEntity item) where TEntity : class, Sita.Entities.IObjectWithChangeTracker, new()
        {
            string EntitySetName;

            EntitySetName = base.CreateObjectSet<TEntity>().EntitySet.Name;

            base.AttachTo(EntitySetName, item);
        }

        public new IObjectSet<TEntity> CreateObjectSet<TEntity>() where TEntity : class, Sita.Entities.IObjectWithChangeTracker, new()
        {
            ObjectSet<TEntity> ReturnSet;

            ReturnSet = base.CreateObjectSet<TEntity>();

            //ReturnSet.MergeOption = MergeOption.NoTracking;

            return ReturnSet;
        }

        public new object GetObjectByKey(EntityKey key)
        {
            return base.GetObjectByKey(key);
        }


        #endregion

        #region IUnitOfWork

        public void Commit()
        {
            IEnumerable<object> DeletedEntities;
            try
            {
                base.DetectChanges();

                DeletedEntities = this.ObjectStateManager.GetObjectStateEntries(EntityState.Modified)
                    .Where(ose => ((Sita.Entities.IObjectWithChangeTracker)ose.Entity).ChangeTracker.State
                        == Sita.Entities.ObjectState.Deleted).Select(ose => ose.Entity);

                for (int i = 0; i < DeletedEntities.Count(); i++)
                {
                    base.DeleteObject(DeletedEntities.ElementAt(i));
                }

                base.SaveChanges();
            }
            catch (Exception)
            {
                RollbackChanges();
                throw;
            }
        }

        public void RollbackChanges()
        {
            IEnumerable<object> RefreshItems;

            RefreshItems = this.ObjectStateManager.GetObjectStateEntries(EntityState.Modified)
                                                                        .Where(ose => !ose.IsRelationship && ose.Entity != null)
                                                                       .Select(ose => ose.Entity);
            this.Refresh(RefreshMode.StoreWins, RefreshItems);
        }

        #endregion

        #region IRoamFixContext


        #endregion

        public void Dettach<TEntity>(TEntity item) where TEntity : class, Sita.Entities.IObjectWithChangeTracker, new()
        {
            base.Detach(item);
        }

        public void CleanObjects()
        {
            IEnumerable<object> RefreshItems;

            RefreshItems = this.ObjectStateManager.GetObjectStateEntries(EntityState.Modified |
                EntityState.Added | EntityState.Deleted | EntityState.Unchanged)
                                                                       .Select(ose => ose.Entity);

            for (int i = 0; i < RefreshItems.Count(); i++)
            {
                this.DeleteObject(RefreshItems.ElementAt(i));
            }

            this.Refresh(RefreshMode.StoreWins, RefreshItems);
        }
    }
}
